/*
 * File:   Conj.h
 * Author: Fede
 *
 * Created on 30 de octubre de 2010, 15:57
 */

#ifndef AED2_CONJ_H_INCLUDED
#define	AED2_CONJ_H_INCLUDED

#include <iostream>
#include "Dicc.h"

namespace aed2 {

    template<class T>
    class Conj{
    public:
        class Iterador;
        class const_Iterador;

        Conj();
        Conj(const Conj<T>& otro);

        Iterador Agregar(const T& e);
        Iterador AgregarRapido(const T& e);
        bool EsVacio() const;
        bool Pertenece(const T& e) const;
        void Eliminar(const T& e);
        Nat Cardinal() const;
        const_Iterador CrearIt() const;
        Iterador CrearIt();

        //esta funcion la agregamos aca, porque nos conviene acceder a
        //la representación.  Sino, no haria falta.
        bool operator==(const Conj<T>& otro) const;

        class const_Iterador{
            typename Dicc<T,bool>::const_Iterador it;
            const_Iterador(const Conj<T>* c);
            friend typename Conj<T>::const_Iterador Conj<T>::CrearIt() const;
        public:
        	const_Iterador() {}
			const_Iterador(const typename Conj<T>::Iterador& otra) : it(otra.it) {}
			const_Iterador(const typename Conj<T>::const_Iterador& otra) : it(otra.it) {}
			const_Iterador& operator=(const typename Conj<T>::const_Iterador& otra)
				{it = otra.it; return *this;}

			bool operator==(const typename Conj<T>::const_Iterador& otro) const {return it == otro.it;}

            bool HaySiguiente()const;
            bool HayAnterior()const;
            const T& Siguiente()const;
            const T& Anterior()const;
            void Avanzar();
            void Retroceder();
        };

        class Iterador{
            typename Dicc<T,bool>::Iterador it;
            Iterador(Conj<T>* c);
            friend typename Conj<T>::Iterador Conj<T>::CrearIt();
            Iterador(const typename Dicc<T,bool>::Iterador& itDict);
            friend typename Conj<T>::Iterador Conj<T>::Agregar(const T&);
            friend typename Conj<T>::Iterador Conj<T>::AgregarRapido(const T&);
            friend class Conj<T>::const_Iterador;
        public:
			Iterador(const typename Conj<T>::Iterador& otra) : it(otra.it) {}
			Iterador& operator=(const typename Conj<T>::Iterador& otra)
				{it = otra.it; return *this;}
			Iterador() {}

			bool operator==(const typename Conj<T>::Iterador& otro) const {return it == otro.it;}

            bool HaySiguiente() const;
            bool HayAnterior() const;
            const T& Siguiente() const;
            const T& Anterior() const;
            void Avanzar();
            void Retroceder();
            void EliminarAnterior();
            void EliminarSiguiente();
        };

    private:
        Dicc<T,bool> d;
    };

    template<class T>
    std::ostream& operator<<(std::ostream&, const Conj<T>&);

    template<class T>
    std::ostream& operator==(const Conj<T>&, const Conj<T>&);



template<class T>
Conj<T>::Conj() {}

template<class T>
Conj<T>::Conj(const Conj<T>& otro): d(otro.d) {}

template<class T>
typename Conj<T>::Iterador Conj<T>::Agregar(const T& e){
    return Iterador(d.Definir(e, true));
}

template<class T>
typename Conj<T>::Iterador Conj<T>::AgregarRapido(const T& e){
    return Iterador(d.DefinirRapido(e, true));
}

template<class T>
bool Conj<T>::EsVacio() const{
    return d.CantClaves()==0;
}

template<class T>
bool Conj<T>::Pertenece(const T& e) const{
    return d.Definido(e);
}


template<class T>
void Conj<T>::Eliminar(const T& e){
    if(Pertenece(e)) d.Borrar(e);
}

template<class T>
Nat Conj<T>::Cardinal() const{
    return d.CantClaves();
}

template<class T>
bool Conj<T>::operator==(const Conj<T>& otro) const {
    return d == otro.d;
}

template<class T>
typename Conj<T>::Iterador Conj<T>::CrearIt(){
    return Iterador(this);
}

template<class T>
typename Conj<T>::const_Iterador Conj<T>::CrearIt() const{
    return const_Iterador(this);
}

template<class T>
Conj<T>::const_Iterador::const_Iterador(const Conj<T>* c):
    it(c->d.CrearIt()){}

template<class T>
Conj<T>::Iterador::Iterador(Conj<T>* c):
    it(c->d.CrearIt()){}

template<class T>
Conj<T>::Iterador::Iterador(const typename Dicc<T,bool>::Iterador& iter):
    it(iter) {}

template<class T>
bool Conj<T>::Iterador::HayAnterior() const{
    return it.HayAnterior();
}

template<class T>
bool Conj<T>::const_Iterador::HayAnterior() const{
    return it.HayAnterior();
}

template<class T>
bool Conj<T>::Iterador::HaySiguiente() const{
    return it.HaySiguiente();
}

template<class T>
bool Conj<T>::const_Iterador::HaySiguiente() const{
    return it.HaySiguiente();
}

template<class T>
const T& Conj<T>::const_Iterador::Siguiente() const{
    assert(HaySiguiente());
    return it.SiguienteClave();
}

template<class T>
const T& Conj<T>::Iterador::Siguiente() const{
    assert(HaySiguiente());
    return it.SiguienteClave();
}

template<class T>
const T& Conj<T>::Iterador::Anterior() const{
    assert(HayAnterior());
    return it.AnteriorClave();
}

template<class T>
const T& Conj<T>::const_Iterador::Anterior() const{
    assert(HayAnterior());
    return it.AnteriorClave();
}

template<class T>
void Conj<T>::Iterador::Avanzar() {
    assert(HaySiguiente());
    it.Avanzar();
}

template<class T>
void Conj<T>::const_Iterador::Avanzar() {
    assert(HaySiguiente());
    it.Avanzar();
}

template<class T>
void Conj<T>::Iterador::Retroceder() {
    assert(HayAnterior());
    it.Retroceder();
}

template<class T>
void Conj<T>::const_Iterador::Retroceder() {
    assert(HayAnterior());
    it.Retroceder();
}

template<class T>
void Conj<T>::Iterador::EliminarAnterior() {
    assert(HayAnterior());
    it.EliminarAnterior();
}

template<class T>
void Conj<T>::Iterador::EliminarSiguiente() {
    assert(HaySiguiente());
    it.EliminarSiguiente();
}

template<class T>
bool operator==(const Conj<T>& c1, const Conj<T>& c2) {
    return c1.operator==(c2);
}

template<class T>
std::ostream& operator<<(std::ostream& os, const Conj<T>& c) {
    return Mostrar(os, c, '{', '}');
}



}

#endif	//AED2_CONJ_H_INCLUDED

